package com.orkasgb.framework.springsecurity.sms;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * 真正认证的处理类，具体实现了根据短信验证码进行身份验证的功能。主要是通过手机号码获取到验证码，进行匹配。
 *
 * @date
 * @since 1.0.0
 */
@Component
public class OrkasgbSMSAuthenticationProvider implements AuthenticationProvider {

    private UserCache userCache = new NullUserCache();

    private final OrkasgbSMSUserDetailsService orkasgbSMSUserDetailsService;

    /**
     * 构造的时候将实际上获取用户信息的实现类注入
     */
    public OrkasgbSMSAuthenticationProvider() {
        this.orkasgbSMSUserDetailsService = new OrkasgbSMSUserDetailsService();
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        OrkasgbSMSAuthenticationToken orkasgbSMSAuthenticationToken = (OrkasgbSMSAuthenticationToken) authentication;
        String phoneNumber = (String) orkasgbSMSAuthenticationToken.getCredentials();
        UserDetails orkasgbSMSUserDetails = this.orkasgbSMSUserDetailsService.loadUserByUsername(phoneNumber);
        if (Objects.isNull(orkasgbSMSUserDetails)) {
            throw new IllegalStateException("User not found");
        }

        // 这里的验证码实际上是从前端传过来的，而实际上保存在后台的验证码是通过orkasgbSMSUserDetailsService从其他存储介质中获取的，
        // 实际上就是前后端的验证做一个匹配验证，匹配不通过将会抛出异常。
        String code = (String) orkasgbSMSAuthenticationToken.getPrincipal();
        if (!StringUtils.equals(code, orkasgbSMSUserDetails.getPassword())) {
            throw new BadCredentialsException("Bad credentials");
        }

        // 验证通过之后，就会构造一个新的Authentication对象，这个是完全认证过的对象，里面有用户的授权信息，并且里面的authenticated属性为true。
        OrkasgbSMSAuthenticationToken orkasgbSMSAuthenticationedToken =
                new OrkasgbSMSAuthenticationToken(phoneNumber, orkasgbSMSUserDetails, orkasgbSMSUserDetails.getAuthorities());
        orkasgbSMSAuthenticationedToken.setDetails(orkasgbSMSUserDetails);

        SecurityContextHolder.getContext().setAuthentication(orkasgbSMSAuthenticationedToken);
        return orkasgbSMSAuthenticationedToken;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return OrkasgbSMSAuthenticationToken.class.isAssignableFrom(authentication);
    }
}